#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <list>
#include <string>
#include <stack>

#include <util.h>
#include <timer.h>

using namespace std;

/** NOTE: Esto tiene que ser una copia exacta de ej3.cpp */
class Digrafo {
	private:
		int m_nodos;
		vector< list<int> > *m_aristas;
	
	public:
		Digrafo(int n) {
			m_nodos = n;
			m_aristas = new vector< list<int> > (n, list<int> () );
		}
		
		~Digrafo() {
			delete m_aristas;
		}
		
		void ponerArtista(int nodo1, int nodo2) {
			(*m_aristas)[nodo1-1].push_back(nodo2);
		}
		
		int nodos() const {
			return m_nodos;
		}
		
		list<int> adyacencias(int nodo) const {
			return (*m_aristas)[nodo-1];
		}
		
		friend ostream& operator<<(ostream &salida, const Digrafo &g) {
			for(int i = 0; i < g.m_nodos; i++) {
				salida << "* " << i+1 << ": ";
				
				list<int> aristas = (*g.m_aristas)[i];
				for(list<int>::iterator it = aristas.begin(); it != aristas.end(); it++) {
					salida << *it << " ";
				}
				salida << endl;
			}
			return salida;
		}
};

class Eleccion {
private:
	vector< vector<int> > *m_votantes_prioridades;
	int m_votantes, m_candidatos;
	
public:
	Eleccion(int votantes, int candidatos) {
		m_votantes_prioridades = new vector< vector<int> > (votantes, vector<int> (candidatos));
		m_votantes = votantes;
		m_candidatos = candidatos;
	}

	~Eleccion() {
		delete m_votantes_prioridades;
	}
	
	void setPrioridad(int votante, int candidato, int prioridad) {
		if(votante < 1 || votante > m_votantes)
			return;
		
		if(candidato < 1 || candidato > m_candidatos)
			return;
		
		(*m_votantes_prioridades)[votante-1][candidato-1] = prioridad;
	}
	
	int enfrentar(int candidato1, int candidato2) const {
		int resultado = 0;
		
		for(int i = 0; i < m_votantes; i++) {
			if((*m_votantes_prioridades)[i][candidato1-1] < (*m_votantes_prioridades)[i][candidato2-1])
				resultado++;
			else if((*m_votantes_prioridades)[i][candidato1-1] > (*m_votantes_prioridades)[i][candidato2-1])
				resultado--;
		}
		
		return resultado;
	}
	
	friend ostream& operator<<(ostream &salida, const Eleccion &e) {
			for(vector< vector<int> >::iterator it = (*e.m_votantes_prioridades).begin(); it != (*e.m_votantes_prioridades).end(); it++) {
				vector<int> fila = *it;
				
				for(vector<int>::iterator it2 = fila.begin(); it2 != fila.end(); it2++) {
					salida << *it2 << " ";
				}
				salida << endl;
			}
			
			return salida;
		}
};

extern string resolver(int votantes, int candidatos, int candidato_actual, const vector< vector<int> > &votaciones);

/** Funciones auxiliares **/
bool en(vector<int> v, int e) {
	for(unsigned int i = 0; i < v.size(); i++) {
		if(v[i] == e) return true;
	}
	
	return false;
}

/** Acá empieza el generador. **/
static int gMin = 1;
static int gMax = 100;

void generarMejorCaso( ostream &salida ) {
}

void generarPeorCaso( ostream &salida ) {
}

void generarCasosAleatorios( ostream &salida ) {
	vector< vector<int> > votaciones;
	Timer t;
	
	ofstream times( "t3-times-aleatorio.txt" );
	ofstream clocks( "t3-clocks-aleatorio.txt" );
	
	srand( time( 0 ) );
	
	for ( int i = gMin; i <= gMax; i++ ) {
		int votantes = i, candidatos = i;
		int candidato_actual = rand() % candidatos + 1;
		
		votaciones = vector< vector<int> > (votantes, vector<int> (candidatos));
		for(int j = 0; j < votantes; j++) {
			for(int k = 0; k < candidatos; k++) {
				int candidato;
				
				do {
					candidato = rand() % candidatos + 1;
				}while(en(votaciones[j], candidato));
				
				votaciones[j][k] = candidato;
			}
		}
		
		t.comenzar();
		resolver(votantes, candidatos, candidato_actual, votaciones);
		t.terminar();
	
		times << i + i << ' ' << t.getTiempo() << endl;
		clocks << i + i << ' ' << t.getCiclos() << endl;
		
		votaciones.clear();
	}
}

bool establecerMaximo( const char *str ) {
	if ( !str2int( str, &gMax ) ) {
		cerr << "Máximo no reconocido, debe ser un número entero.\n";
		return false;
	}
	return true;
}

bool establecerMinimo( const char *str ) {
	if ( !str2int( str, &gMin ) ) {
		cerr << "Mínimo no reconocido, debe ser un número entero.\n";
		return false;
	}
	return true;
}
